package cn.leo.dynamic_multi_datasource.config;

import cn.leo.dynamic_multi_datasource.datasource.DynamicDatasourceContextHolder;
import cn.leo.dynamic_multi_datasource.datasource.DynamicRoutingDataSource;
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.bind.RelaxedDataBinder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * @author leo.z.l
 * @create 2019-09-07  16:27
 */
@Configuration
@EnableTransactionManagement
public class DruidDatasourceConfig{

    public final String SPLIT_DATASOURCE_NAMES = ",";

    @Autowired
    public DatasourceConfig datasourceConfig;

    LinkedHashMap<Object, Object> targetDatasource = new LinkedHashMap<>();

    private List<String> customDataSourceNames = new ArrayList<>();

    private Logger logger = LogManager.getLogger(DruidDatasourceConfig.class);

    private ConversionService conversionService = new DefaultConversionService();


    @Bean(name = "dataSource")
    @Primary
    public AbstractRoutingDataSource dataSource() {
        DynamicRoutingDataSource dynamicDataSource = new DynamicRoutingDataSource();
        initCustomDataSources();
        dynamicDataSource.setDefaultTargetDataSource(targetDatasource.get(customDataSourceNames.get(0)));
        dynamicDataSource.setTargetDataSources(targetDatasource);
        dynamicDataSource.afterPropertiesSet();
        return dynamicDataSource;
    }

    /**
     * 初始化數據源
     */
    private void initCustomDataSources() {

        //獲取數據源的名稱
        Map<String, Object> druidConfig = datasourceConfig.getDruid();
        Map<String, Object> mulitiDatasourceConfig = datasourceConfig.getMulitidatasource();

        String dataSourceNames = (String) mulitiDatasourceConfig.get("name");

        if (StringUtils.isEmpty(dataSourceNames)) {
            logger.error("The multiple data source list are empty.");
        } else {

            Map<String, Object> druidValuesMaps = (Map<String, Object>) druidConfig.get("druid");

            MutablePropertyValues dataSourcePropertyValue = new MutablePropertyValues(druidValuesMaps);

            for (String dataSourceName : dataSourceNames.split(SPLIT_DATASOURCE_NAMES)) {
                try {
                    Map<String, Object> customerDatasourceConfig = (Map<String, Object>) mulitiDatasourceConfig.get(dataSourceName);

                    customerDatasourceConfig.forEach((key, value) -> dataSourcePropertyValue.addPropertyValue(key,value));


                    DataSource ds = dataSourceBuild(dataSourcePropertyValue);

                    if (null != ds) {
                        if (ds instanceof DruidDataSource) {
                            DruidDataSource druidDataSource = (DruidDataSource) ds;
                            druidDataSource.setName(dataSourceName);

                            //初始化德魯伊的過濾器
                            //initDruidFilters(druidDataSource);
                        }

                        customDataSourceNames.add(dataSourceName);
                        DynamicDatasourceContextHolder.datasourceIds.add(dataSourceName);
                        targetDatasource.put(dataSourceName, ds);

                    }
                    logger.info("Data source initialization 【" + dataSourceName + "】 successfully ...");
                } catch (Exception e) {
                    logger.error("Data source initialization【" + dataSourceName + "】 failed ...", e);
                }
            }
        }
    }


    /**
     * @param dataSourcePropertyValue 数据源创建所需参数
     * @return DataSource 创建的数据源对象
     * @Title: DataSourceBuild
     * @Description: 创建数据源
     */
    public DataSource dataSourceBuild(MutablePropertyValues dataSourcePropertyValue) {

        DataSource ds = null;

        if (dataSourcePropertyValue.isEmpty()) {
            return ds;
        }

        //获取连接池的类型
        String type = dataSourcePropertyValue.get("type").toString();

        if (StringUtils.isNotEmpty(type)) {
            //对druid连接池进行初始化，非druid需要重新判断
            if (StringUtils.equals(type, DruidDataSource.class.getTypeName())) {
                ds = initDruidDatasource(dataSourcePropertyValue);
            }
        }
        return ds;
    }

    private DataSource initDruidDatasource(MutablePropertyValues dataSourcePropertyValue) {
        DataSource ds;
        ds = new DruidDataSource();

        RelaxedDataBinder dataBinder = new RelaxedDataBinder(ds);
        dataBinder.setConversionService(conversionService);
        dataBinder.setIgnoreInvalidFields(false);
        dataBinder.setIgnoreNestedProperties(false);
        dataBinder.setIgnoreUnknownFields(true);
        dataBinder.bind(dataSourcePropertyValue);
        return ds;
    }

    /**
     * 下面是其他的过滤器等配置，非必要
     */
    //@Bean
    //public ServletRegistrationBean statViewServlet() {
    //
    //    RelaxedPropertyResolver property =
    //            new RelaxedPropertyResolver(environment, "spring.datasource.druid.");
    //
    //    Map<String, Object> druidPropertiesMaps = property.getSubProperties("stat-view-servlet.");
    //
    //
    //    boolean statViewServletEnabled = false;
    //    //String statViewServletEnabledKey = AppConstant.ENABLED_ATTRIBUTE_NAME;
    //    ServletRegistrationBean registrationBean = null;
    //
    //    if (druidPropertiesMaps.containsKey(statViewServletEnabledKey)) {
    //        String statViewServletEnabledValue =
    //                druidPropertiesMaps.get(statViewServletEnabledKey).toString();
    //        statViewServletEnabled = Boolean.parseBoolean(statViewServletEnabledValue);
    //    }
    //    if (statViewServletEnabled) {
    //        registrationBean = new ServletRegistrationBean();
    //        StatViewServlet statViewServlet = new StatViewServlet();
    //
    //        registrationBean.setServlet(statViewServlet);
    //
    //        String urlPatternKey = "url-pattern";
    //        String allowKey = "allow";
    //        String denyKey = "deny";
    //        String usernameKey = "login-username";
    //        String secretKey = "login-password";
    //        String resetEnableKey = "reset-enable";
    //
    //        if (druidPropertiesMaps.containsKey(urlPatternKey)) {
    //            String urlPatternValue =
    //                    druidPropertiesMaps.get(urlPatternKey).toString();
    //            registrationBean.addUrlMappings(urlPatternValue);
    //        } else {
    //            registrationBean.addUrlMappings("/druid/*");
    //        }
    //
    //        addBeanParameter(druidPropertiesMaps, registrationBean, "allow", allowKey);
    //        addBeanParameter(druidPropertiesMaps, registrationBean, "deny", denyKey);
    //        addBeanParameter(druidPropertiesMaps, registrationBean, "loginUsername", usernameKey);
    //        addBeanParameter(druidPropertiesMaps, registrationBean, "loginPassword", secretKey);
    //        addBeanParameter(druidPropertiesMaps, registrationBean, "resetEnable", resetEnableKey);
    //    }
    //
    //    return registrationBean;
    //}

    //@Bean
    //public FilterRegistrationBean filterRegistrationBean() {
    //    RelaxedPropertyResolver property =
    //            new RelaxedPropertyResolver(environment, "spring.datasource.druid.");
    //
    //    Map<String, Object> druidPropertiesMaps = property.getSubProperties("web-stat-filter.");
    //
    //
    //    boolean webStatFilterEnabled = false;
    //    String webStatFilterEnabledKey = AppConstant.ENABLED_ATTRIBUTE_NAME;
    //    FilterRegistrationBean registrationBean = null;
    //    if (druidPropertiesMaps.containsKey(webStatFilterEnabledKey)) {
    //        String webStatFilterEnabledValue =
    //                druidPropertiesMaps.get(webStatFilterEnabledKey).toString();
    //        webStatFilterEnabled = Boolean.parseBoolean(webStatFilterEnabledValue);
    //    }
    //    if (webStatFilterEnabled) {
    //        registrationBean = new FilterRegistrationBean();
    //        WebStatFilter filter = new WebStatFilter();
    //        registrationBean.setFilter(filter);
    //
    //        String urlPatternKey = "url-pattern";
    //        String exclusionsKey = "exclusions";
    //        String sessionStatEnabledKey = "session-stat-enable";
    //        String profileEnabledKey = "profile-enable";
    //        String principalCookieNameKey = "principal-cookie-name";
    //        String principalSessionNameKey = "principal-session-name";
    //        String sessionStateMaxCountKey = "session-stat-max-count";
    //
    //        if (druidPropertiesMaps.containsKey(urlPatternKey)) {
    //            String urlPatternValue =
    //                    druidPropertiesMaps.get(urlPatternKey).toString();
    //            registrationBean.addUrlPatterns(urlPatternValue);
    //        } else {
    //            registrationBean.addUrlPatterns("/*");
    //        }
    //
    //        if (druidPropertiesMaps.containsKey(exclusionsKey)) {
    //            String exclusionsValue =
    //                    druidPropertiesMaps.get(exclusionsKey).toString();
    //            registrationBean.addInitParameter("exclusions", exclusionsValue);
    //        } else {
    //            registrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
    //        }
    //
    //        addBeanParameter(druidPropertiesMaps, registrationBean, "sessionStatEnable", sessionStatEnabledKey);
    //        addBeanParameter(druidPropertiesMaps, registrationBean, "profileEnable", profileEnabledKey);
    //        addBeanParameter(druidPropertiesMaps, registrationBean, "principalCookieName", principalCookieNameKey);
    //        addBeanParameter(druidPropertiesMaps, registrationBean, "sessionStatMaxCount", sessionStateMaxCountKey);
    //        addBeanParameter(druidPropertiesMaps, registrationBean, "principalSessionName", principalSessionNameKey);
    //    }
    //    return registrationBean;
    //}

    //private void addBeanParameter(Map<String, Object> druidPropertyMap, RegistrationBean registrationBean, String paramName, String propertyKey) {
    //    if (druidPropertyMap.containsKey(propertyKey)) {
    //        String propertyValue =
    //                druidPropertyMap.get(propertyKey).toString();
    //        registrationBean.addInitParameter(paramName, propertyValue);
    //    }
    //}

    //private void initDruidFilters(DruidDataSource druidDataSource) {
    //
    //    List<Filter> filters = druidDataSource.getProxyFilters();
    //
    //    RelaxedPropertyResolver filterProperty =
    //            new RelaxedPropertyResolver(environment, "spring.datasource.druid.filter.");
    //
    //
    //    String filterNames = environment.getProperty("spring.datasource.druid.filters");
    //
    //    String[] filterNameArray = filterNames.split("\\,");
    //
    //    for (int i = 0; i < filterNameArray.length; i++) {
    //        String filterName = filterNameArray[i];
    //        Filter filter = filters.get(i);
    //
    //        Map<String, Object> filterValueMap = filterProperty.getSubProperties(filterName + ".");
    //        String statFilterEnabled = filterValueMap.get(ENABLED_ATTRIBUTE_NAME).toString();
    //        if (statFilterEnabled.equals("true")) {
    //            MutablePropertyValues propertyValues = new MutablePropertyValues(filterValueMap);
    //            RelaxedDataBinder dataBinder = new RelaxedDataBinder(filter);
    //            dataBinder.bind(propertyValues);
    //        }
    //    }
    //}
}
